/* USER CODE BEGIN Header */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

#include "fonts.h"
#include "ssd1306.h"




/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
TIM_HandleTypeDef htim2;

volatile uint32_t cnt;
volatile uint32_t adc;
volatile uint32_t timer;

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void GPIO_Init(void);
static void MX_I2C1_Init(void);
static void TIM2_Init(void);
static void TIM3_Init(void);
static void ADC_Init(void);
void showGreetings();
void showData();
uint16_t get_ADC_value(void);

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  GPIO_Init();
  TIM2_Init();		//encoder
  TIM3_Init();		//pwm
  MX_I2C1_Init();	//lcd
  SSD1306_Init();
  ADC_Init();

  /*Enable interrupt*/
  //NVIC_EnableIRQ(TIM3_IRQn); //TODO handle this


  /*
  void TIM3_IRQHandler(void){
	 TIM3->SR &= TIM_SR_UIF;
 }
 */

  showGreetings();
  SSD1306_Clear();

  /* Infinite loop */
  while(1){

	  if(((GPIOC->IDR >> 14) & 0x01))
		  GPIOC->BSRR = GPIO_BSRR_BS13;
	  else
		  GPIOC->BSRR = GPIO_BSRR_BR13;

	  cnt = TIM2->CNT;
	  adc = get_ADC_value();
	  //timer = TIM3->CNT;

	  TIM3->CCR1 = cnt;
	  TIM3->CCR2 = adc/40;

	  showData(cnt, adc);

  }
}

/**
  * @brief Show parameters
  * @param None
  * @retval None
  */
void showData(uint32_t cnt_value, uint32_t adc_value){

	char cnt_temp[5];
	char adc_temp[5];
	itoa(cnt_value, cnt_temp, 10);
	itoa(adc_value, adc_temp, 10);

	//clear lcd
	SSD1306_GotoXY (44,0);
	SSD1306_Puts ("     ", &Font_11x18, 1);
	SSD1306_GotoXY (44,32);
	SSD1306_Puts ("     ", &Font_11x18, 1);

	SSD1306_GotoXY (0,0);
	SSD1306_Puts ("cnt=", &Font_11x18, 1);

	SSD1306_GotoXY (44,0);
	SSD1306_Puts (cnt_temp, &Font_11x18, 1);

	SSD1306_GotoXY (0, 32);
	SSD1306_Puts ("adc=", &Font_11x18, 1);

	SSD1306_GotoXY (44,32);
	SSD1306_Puts (adc_temp, &Font_11x18, 1);

	SSD1306_UpdateScreen();
}


/**
  * @brief Show greetings and logo
  * @param None
  * @retval None
  */
void showGreetings(){
  SSD1306_Clear();
  SSD1306_GotoXY (0,0);
  SSD1306_Puts ("PET", &Font_16x26, 1);
  SSD1306_GotoXY (0, 32);
  SSD1306_Puts ("RECYCLER", &Font_16x26, 1);
  SSD1306_UpdateScreen();
  HAL_Delay(1000);
  SSD1306_Clear();
  SSD1306_GotoXY (0,0);
  SSD1306_Puts ("by John", &Font_16x26, 1);
  SSD1306_GotoXY (0, 32);
  //SSD1306_Puts ("XXXXXXXXXXXXXX", &Font_11x18, 1);
  SSD1306_Puts ("   Pank", &Font_16x26, 1);
  SSD1306_UpdateScreen();
  HAL_Delay(1000);
}


/**
  * @brief ADC Initialization Function
  * @param None
  * @retval uint 16_t adc value
  */
uint16_t get_ADC_value(void){

	ADC1->CR2 |= ADC_CR2_SWSTART;	//start conversion
	while(!(ADC1->SR & ADC_SR_EOC)){} 	//wait conversion result

	return ADC1->DR;
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct = {0};
	RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

	/** Initializes the RCC Oscillators according to the specified parameters
	  * in the RCC_OscInitTypeDef structure.
	  */
	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
	RCC_OscInitStruct.HSEState = RCC_HSE_ON;
	RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
	RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
	if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
	{
	  Error_Handler();
	}

	/** Initializes the CPU, AHB and APB buses clocks
	*/
	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
	                            |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

	if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
	{
	  Error_Handler();
	}
}

/**
  * @brief I2C2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 400000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}


/**
  * @brief TIM2 Initialization Function (Encoder mode). Encoder connect to PA0 and PA1
  * @param None
  * @retval None
  */
static void TIM2_Init(void){

	//конфигурация таймера2 для энкодера
	RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;                   //тактирование таймера4
	TIM2->CCMR1   = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;  //полярность сигнала для каждого входа
	TIM2->CCER    = TIM_CCER_CC1P | TIM_CCER_CC2P;
	TIM2->SMCR    = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;      //режим энкодера
	TIM2->ARR     = 80;                                   //значение, до которого считает CNT
	TIM2->CNT     = 0;                                    //начальное значение счётчика
	TIM2->CR1     = TIM_CR1_CEN;                          //включаем таймер
}

/**
  * @brief TIM3 Initialization Function (2 PWM channel 1-2). PWM on PA6 and PA7
  * @param None
  * @retval None
  */
static void TIM3_Init(void){


	  RCC->APB1ENR  |= RCC_APB1ENR_TIM3EN;                                // Включаем тактирование таймера
	  TIM3->PSC     = 7199;                                              // При тактовой частоте 72 МГц, тактирование таймера 10КГц
	  TIM3->ARR     = 100;                                               // Период ШИМ. Тактовая частота ШИМ будет равняться 10 000/100=100Гц
	  TIM3->CCMR1   |= (0b110 << TIM_CCMR1_OC1M_Pos);                     // Включаем PWM первого типа ch1
	  TIM3->CCMR1   |= (0b110 << TIM_CCMR1_OC2M_Pos);                     // Включаем PWM первого типа ch2
	  TIM3->CCER    |= (TIM_CCER_CC1E | TIM_CCER_CC2E);                                     // Разрешаем первому and 2 каналу плеваться на выход
	  TIM3->CR1     |= TIM_CR1_CEN;                                       // Включаем таймер

	  TIM3->CCR1    = 0;                                                // Коэффициент заполнения ШИМ 0% (При таких значениях делителей).
	  TIM3->CCR2    = 0;                                                // Коэффициент заполнения ШИМ 0% (При таких значениях делителей).
	  /*
	   * С этого момента на выводе PA0 должен появиться ШИМ
	   */
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void GPIO_Init(void)
{

	//enable port A
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

	//enable port B
	RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

	//enable port C
	RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;

	//PC13 as out
	GPIOC->CRH &= ~GPIO_CRH_MODE13;				//clear MODE_CRH13
	GPIOC->CRH &= ~GPIO_CRH_CNF13;				//clear CNF_CRH13
	GPIOC->CRH |= (0x01<<GPIO_CRH_MODE13_Pos);	//out mode 10 MHz
	GPIOC->CRH |= (0x00<<GPIO_CRH_CNF13_Pos);	//push-pull
	GPIOC->BSRR = GPIO_BSRR_BS13;				//pull-up

	//PC14 as input
	GPIOC->CRH &= ~GPIO_CRH_MODE14;				//clear MODE_CRH14 (input mode)
	GPIOC->CRH &= ~GPIO_CRH_CNF14;				//clear CNF_CRH14
	GPIOC->CRH |= (GPIO_CRH_CNF14_1);			//push-pull
	GPIOC->BSRR = GPIO_BSRR_BS14;				//pull to Vcc

	//PA3 to analog input
	GPIOC->CRL |=(0x00<GPIO_CRL_MODE3_Pos);		//PA3 is input
	GPIOC->CRL |=(0x00<GPIO_CRL_CNF3_Pos);		//PA3 is analog

	//enable alternative func
	RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

	//PA6 and PA7 as PWM out TIM3
	GPIOA->CRL &= ~GPIO_CRL_MODE6; 				//clear MODE_CRL6
	GPIOA->CRL &= ~GPIO_CRL_CNF6; 				//clear CNF_CRL6
	GPIOA->CRL |= (0x2<<GPIO_CRL_CNF6_Pos); 	//set alt func and push-pull for PA6
	GPIOA->CRL |= (0x3<<GPIO_CRL_MODE6_Pos); 	//set speed 50 MHz for PA6

	GPIOA->CRL &= ~GPIO_CRL_MODE7; 				//clear MODE_CRL7
	GPIOA->CRL &= ~GPIO_CRL_CNF7; 				//clear CNF_CRL7
	GPIOA->CRL |= (GPIO_CRL_CNF7_1); 	//set alt func and push-pull for PA7
	GPIOA->CRL |= (GPIO_CRL_MODE7_1 | GPIO_CRL_MODE7_0); 	//set speed 50 MHz for PA7


	/* GPIO Ports Clock Enable */
	 // __HAL_RCC_GPIOD_CLK_ENABLE();
	 // __HAL_RCC_GPIOB_CLK_ENABLE();

}

/**
  * @brief ADC Initialization Function
  * @param None
  * @retval None
  */
static void ADC_Init(void){

	RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;		//enable ADC1 clock

	ADC1->CR1 &= ~(ADC_CR1_JEOCIE);			//EOC interrupt disable
	ADC1->CR1 &= ~(ADC_CR1_AWDIE);			//analog watchdog interrupt disable
	ADC1->CR1 &= ~(ADC_CR1_JEOSIE);			//injected channels interrupt disable
	//ADC1->CR1 |= ADC_CR1_SCAN;			//enable scan mode
	ADC1->CR1 |= (0b0110 << ADC_CR1_DUALMOD_Pos);	//regular channel only

	ADC1->SMPR2 |= (ADC_SMPR2_SMP3_0 | ADC_SMPR2_SMP3_1 | ADC_SMPR2_SMP3_2);	//set 239.5 cycles rate for ch3 adc (pa3)
	ADC1->SQR1 |= (0b000 << ADC_SQR1_L_Pos); 		//quantity adc channels to convert (1)
	ADC1->SQR3 |= (0b00011 << ADC_SQR3_SQ1_Pos);		//first conversion ch3
	//ADC1->SQR3 |= (ADC_SQR3_SQ1_0 | ADC_SQR3_SQ1_1);

	ADC1->CR2 |= ADC_CR2_EXTSEL;	//start conversion by SWSTART bit (program start)
	ADC1->CR2 |= ADC_CR2_EXTTRIG;	//External trigger conversion mode for regular channels
	ADC1->CR2 |= ADC_CR2_ADON;		//AD converter ON/OFF
	ADC1->CR2 |= ADC_CR2_CAL;		//start adc calibration
	while (!(ADC1->CR2 & ADC_CR2_CAL)){} //wait end of calibration

	//ADC1->CR2 |= ADC_CR2_SWSTART;	//start conversion

}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
